2 сентября 2026 г.

Caddy: веб-сервер с автоматическим HTTPS. Установка и первый конфиг

Nginx + Certbot + продление в cron - это три движущиеся части там, где хватило бы одной. Caddy сам выпускает и продлевает TLS-сертификаты, а его конфиг - несколько строк. Ставим на Ubuntu, пишем Caddyfile для статики и для прокси на приложение, разбираем, как работает ACME.

Настройка веб-сервера Caddy - это один apt-репозиторий, три-четыре строки в конфиге и ноль возни с сертификатами. Caddy сам получает TLS-сертификат, как только домен появляется в активной конфигурации, заранее его продлевает и умеет работать обратным прокси. Если вы держите небольшой сайт или приложение на VPS и устали от связки Nginx + Certbot + задача в cron на продление, ниже - как поставить Caddy на Ubuntu 22.04, 24.04 и 26.04 и написать первый конфиг: для статического сайта и для прокси на приложение.

TL;DR. Подключите официальный apt-репозиторий Caddy (он на Cloudsmith), поставьте пакет caddy - вместе с ним придёт systemd-сервис. Опишите сайт в /etc/caddy/Caddyfile: для статики - root и file_server, для приложения - reverse_proxy localhost:3000. Проверьте конфиг командой caddy validate, примените через systemctl reload caddy. Домен должен A- и/или AAAA-записью указывать на сервер, а из портов 80 и 443 снаружи должен быть доступен хотя бы один: тогда Caddy сам получит публично доверенный сертификат, обычно через Let's Encrypt, с ZeroSSL как запасным вариантом. Сертификаты и ключи лежат в /var/lib/caddy/.local/share/caddy, логи - в journalctl -u caddy.

Что делает Caddy такого, чего не делает Nginx + Certbot

Caddy - веб-сервер на Go, из той же категории, что Nginx или Apache: отдаёт статические файлы, проксирует запросы на приложения, терминирует HTTPS. Разница в одном: здесь HTTPS включён по умолчанию. Certbot - это утилита Let's Encrypt для выпуска сертификатов; с Nginx её ставят отдельно, настраивают плагин или webroot и добавляют системный таймер на продление. Caddy делает всё это внутри себя. Как только домен попадает в активную конфигурацию, Caddy в фоне обращается к центру сертификации, проходит проверку владения, кладёт сертификат в память и на диск, дальше продлевает заранее - примерно за треть срока до истечения. Ждать первого запроса пользователя для этого не нужно, отдельного демона, задачи в cron и перезапуска - тоже.

На конфиге разница такая же заметная. Server-блок Nginx под HTTPS-прокси - это 15-20 строк с listen 443 sslssl_certificate, набором proxy_set_header. В Caddyfile то же самое - две строки. Caddy не вытесняет Nginx во всех сценариях (об этом в конце), но для типовой задачи «один-три сайта на VPS, нужен HTTPS и прокси на бэкенд» он убирает почти всю рутину.

Перед установкой заблокируйте доступ к серверу

Caddy будет слушать TCP-порты 80 и 443, но сам firewall не трогает. Если эти порты разрешены на входящие, веб-сервер станет доступен из интернета, то есть машина становится видимой снаружи. Если VPS только что создан, сначала закройте лишние порты и настройте вход по ключу - это отдельная тема, см. «Защита свежего VPS». Дальше считаем, что root или sudo-пользователь у вас есть, а firewall пропускает входящие на 80 и 443 (TCP, а для HTTP/3 ещё UDP 443).

Как установить и настроить веб-сервер Caddy на Ubuntu 22.04, 24.04 и 26.04

Ставим из официального репозитория проекта - он размещён на Cloudsmith. Для Ubuntu 24.04 и 26.04 пакет caddy есть и в репозитории самой Ubuntu, но там заметно более старая ветка; в Ubuntu 22.04 пакета Caddy в стандартном репозитории нет вовсе. Репозиторий проекта даёт актуальный стабильный релиз и обновления обычным apt update. Первый блок ставит зависимости, кладёт публичный ключ репозитория и записывает его адрес.

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list

  • debian-keyringdebian-archive-keyring - наборы ключей, которыми apt проверяет подписи репозиториев.
  • gpg --dearmor -o ...caddy-stable-archive-keyring.gpg - кладёт ключ Caddy туда, где apt его ждёт.
  • второй curl пишет файл со строкой репозитория в /etc/apt/sources.list.d/tee здесь нужен, потому что запись идёт от root.
  • две команды chmod o+r открывают ключ и файл-список на чтение служебному пользователю apt (_apt). На «зажатых» образах с жёстким umask без них apt update падает с Permission denied.

Теперь обновляем индекс пакетов и ставим Caddy.

sudo apt update
sudo apt install caddy

Что вы должны увидеть. В выводе apt update - строка про репозиторий Caddy (...cloudsmith.io/public/caddy/stable...) без ошибок GPG. Если apt ругается на просроченный ключ (EXPKEYSIG), удалите старый ключ и запишите заново: sudo rm /usr/share/keyrings/caddy-stable-archive-keyring.gpg, затем повторите строку с curl ... gpg.key - ключ репозитория периодически перевыпускают. После apt install caddy пакет создаёт системного пользователя caddy, кладёт бинарник в /usr/bin/caddy, конфиг-заготовку в /etc/caddy/Caddyfile и запускает systemd-сервис caddy. systemd - штатная система запуска сервисов в Linux: поднимает процесс при загрузке машины и перезапускает его, если тот упал.

Проверяем, что всё встало.

caddy version
systemctl status caddy

Что вы должны увидеть. caddy version печатает строку вида v2.11.4 h1:...systemctl status caddy - зелёное active (running). Если сразу открыть в браузере http://IP-сервера, Caddy отдаст страницу-заглушку со ссылкой на документацию - значит, сервис живой. Эта заготовка обслуживает только заглушку на порту 80; дальше вы её замените своим конфигом.

Как работает автоматический HTTPS

Когда в Caddyfile адрес сайта - это доменное имя (не IP и не localhost), Caddy сам включает HTTPS. Механизм - ACME (Automatic Certificate Management Environment), стандартный протокол выпуска сертификатов; по нему же работает Certbot. По умолчанию Caddy пробует два центра сертификации подряд: сначала Let's Encrypt, затем ZeroSSL. Управление сертификатами Caddy запускает сразу после загрузки конфигурации и ведёт в фоне - первого запроса пользователя не ждёт.

Чтобы выдать сертификат, центр сертификации должен убедиться, что домен ваш. Caddy отвечает на один из проверочных запросов (challenge): HTTP-01 на порту 80 или TLS-ALPN-01 на порту 443 - достаточно, чтобы снаружи был доступен любой из этих двух портов, а домен A- и/или AAAA-записью указывал на этот сервер. Если оба порта закрыты firewall или заняты Nginx, проверка не пройдёт, и в логах будет ошибка ACME. Обойти требование входящих 80/443 можно проверкой DNS-01 (нужен плагин под вашего DNS-провайдера и пересборка через xcaddy) - тогда открытые порты для выпуска не нужны вовсе.

Для localhost и внутренних имён публично доверенный сертификат обычно не используется. Для них, а по умолчанию и для IP-адресов и всего, где вы явно написали tls internal, Caddy поднимает собственный локальный центр сертификации и подписывает сертификат сам (публично доверенный сертификат на IP в принципе возможен у некоторых центров, но это не путь по умолчанию). Браузер такому сертификату не доверяет, пока вы не добавите корневой сертификат Caddy в доверенные хранилища - он лежит в /var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt. Для внутренних сервисов и локальной разработки этого достаточно.

Сервис caddy работает от пользователя caddy с домашним каталогом /var/lib/caddy. Сертификаты, приватные ключи и данные ACME хранятся в /var/lib/caddy/.local/share/caddy (внутри - подкаталог certificates). Автосохранённый JSON-конфиг - в /var/lib/caddy/.config/caddy. Пока сервис работает штатно, эти файлы трогать не нужно: продление идёт само.

Первый Caddyfile: статический сайт

Caddyfile - основной конфиг Caddy, по умолчанию /etc/caddy/Caddyfile. Синтаксис короткий: строка с адресом сайта, дальше в фигурных скобках - директивы. Заменим заготовку на раздачу статики из каталога. Заранее положите файлы сайта, например в /var/www/example.com, и проверьте, что example.com A- и/или AAAA-записью указывает на сервер (если остался старый AAAA на другую машину - уберите его, иначе ACME будет вести себя странно). Убедитесь, что пользователь caddy может читать эти файлы и заходить в каталоги по пути (право на чтение и x на директориях) - иначе вместо страницы будет 403. Приведите /etc/caddy/Caddyfile к такому виду:

example.com {
root * /var/www/example.com
file_server
encode zstd gzip
}

  • example.com - адрес сайта. Домен без http:// - сигнал Caddy включить HTTPS.
  • root * /var/www/example.com - корневой каталог сайта; * означает «для всех путей запроса».
  • file_server - отдавать файлы с диска.
  • encode zstd gzip - сжимать ответы (zstd, с откатом на gzip). Необязательно, но почти всегда полезно.

Перед применением проверьте конфиг. caddy fmt приводит отступы к единому виду, caddy validate читает конфиг и говорит, корректен ли синтаксис и где ошибка. Делайте это перед каждым reload.

sudo caddy fmt --overwrite /etc/caddy/Caddyfile
sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile

Что вы должны увидеть. caddy validate при успехе печатает Valid configuration. Если есть ошибка, он назовёт строку и причину - правьте и запускайте снова. Теперь применяем без остановки сервиса:

sudo systemctl reload caddy

Команда завершается молча, без вывода - это нормально. Через несколько секунд проверьте результат:

curl -I https://example.com
journalctl -u caddy -n 30 --no-pager

Что вы должны увидеть. В ответе curl - успешный HTTP-ответ без ошибки TLS; конкретный код (200301, ...) и версия протокола зависят от сайта и сборки curl. В логах - запись про certificate obtained successfully для example.com. Если сертификат ещё выпускается, повторите curl через полминуты. Ошибка вида SSL certificate problem в первые секунды после reload - обычно просто гонка: подождите и проверьте ещё раз.

Caddyfile для обратного прокси на приложение (localhost:3000)

Обратный прокси (reverse proxy) - сервер, который принимает запросы снаружи и передаёт их приложению внутри машины, а ответ возвращает клиенту. Адрес, куда прокси шлёт запросы, называют upstream. Схема нужна, когда ваш сервис на Node.js, Python или Go слушает localhost:3000, а наружу его надо отдавать по HTTPS на 443. В Caddyfile это выглядит так:

app.example.com {
reverse_proxy localhost:3000
}

  • app.example.com - поддомен, A-запись на тот же сервер.
  • reverse_proxy localhost:3000 - слать запросы на приложение по этому адресу. Для upstream по HTTP Caddy передаёт исходный Host клиента без изменений и добавляет X-Forwarded-ForX-Forwarded-Proto и X-Forwarded-Host - приложение видит реальный адрес, протокол и хост клиента. (Для сравнения: proxy_pass в Nginx по умолчанию переписывает Host на адрес upstream - Caddy так не делает.)

Несколько сайтов в одном файле - это просто несколько блоков подряд, статических и прокси вперемешку. После правки снова прогоните caddy validate и systemctl reload caddy, затем проверьте:

curl -I https://app.example.com

Что вы должны увидеть. Успешный ответ или тот код, что отдаёт само приложение (200302, ...). Если пришло 502 Bad Gateway - прокси работает, но upstream недоступен: проверьте, слушает ли сервис порт 3000.

sudo ss -tlnp | grep 3000

Пустой вывод означает, что на 3000 никто не слушает - запустите приложение или поправьте порт в конфиге.

reload или restart, и где что лежит

reload применяет новый конфиг без остановки сервиса и без разрыва соединений: Caddy поднимает новую конфигурацию рядом и переключается на неё. Для правок Caddyfile всегда используйте его. restart останавливает и заново запускает процесс, то есть даёт короткий простой; он нужен, только если сервис завис или вы меняли сам unit-файл (тогда сначала sudo systemctl daemon-reload). Под капотом systemctl reload caddy вызывает caddy reload --config /etc/caddy/Caddyfile --force.

Что

Где

Основной конфиг

/etc/caddy/Caddyfile

Бинарник

/usr/bin/caddy

Сертификаты, ключи, данные ACME

/var/lib/caddy/.local/share/caddy

Автосохранённый JSON-конфиг

/var/lib/caddy/.config/caddy

Unit systemd

/usr/lib/systemd/system/caddy.service

Логи

journalctl -u caddy

journalctl -u caddy - это служебные логи Caddy: старт, выпуск и продление сертификатов, ошибки. Логи запросов (access logs) по умолчанию выключены - их включают директивой log в Caddyfile.

Caddy или Nginx: когда что

Аспект

Caddy

Nginx

TLS-сертификаты

выпускает и продлевает сам

отдельно Certbot + системный таймер

Конфиг HTTPS-прокси

2-3 строки

15-20 строк

Формат конфига

Caddyfile или JSON через API

собственный синтаксис

Применение изменений

reload без простоя

reload без простоя

HTTP/3 (QUIC)

из коробки

с 1.25, отдельной директивой

Расширения

плагины, пересборка через xcaddy

модули, часто пересборка; готовых больше

Статика под высокой нагрузкой

хорошо

традиционно чуть быстрее, тоньше тюнится

Экосистема и примеры

меньше

огромная, почти любой кейс уже описан

Оставайтесь на Nginx, если: у вас уже есть большой рабочий конфиг и нет причин его переписывать; нужен тонкий контроль над TLS - конкретные шифры и версии, нестандартные сценарии с клиентскими сертификатами; логика маршрутизации и rewrite сложная и в Nginx выражается проще; нужны его модули (RTMP, широкий Lua/OpenResty); важны формальная поддержка и то, что Nginx лежит в основном репозитории Ubuntu. В остальных случаях Caddy экономит время: HTTPS и продление перестают быть задачей, конфиг читается целиком за минуту, обратный прокси - одна строка.

Частые вопросы

Нужен ли Caddy root-доступ?

Сам сервис работает от системного пользователя caddy, но sudo нужен при установке и для правок конфига в /etc/caddy. Право слушать порты 80 и 443 выдано процессу через capability в unit-файле, отдельных действий не требует. Для локального центра сертификации Caddy пытается добавить свой корневой сертификат в системное хранилище - под сервисным пользователем это может не сработать, тогда добавьте его вручную из data-каталога.

Можно ли поставить свой сертификат вместо Let's Encrypt?

Да. В блоке сайта укажите tls /path/fullchain.pem /path/privkey.pem, и Caddy возьмёт ваши файлы вместо ACME. Так делают, когда сертификат выдан корпоративным центром или куплен у коммерческого поставщика.

Что будет, если порт 80 закрыт?

Проверка HTTP-01 не пройдёт. Caddy попробует TLS-ALPN-01 на 443; если и он недоступен, сертификат не выпустится, в логах будет ошибка ACME. Откройте оба порта или переключитесь на DNS-проверку - для неё нужен плагин под вашего DNS-провайдера и пересборка бинарника через xcaddy.

Поддерживает ли Caddy HTTP/3?

Да, HTTP/3 поверх QUIC (UDP 443) включён по умолчанию начиная с Caddy 2.6. Клиенты, которые его не умеют, работают по HTTP/2. Проверьте, что firewall пропускает входящий UDP на 443, иначе часть клиентов молча откатится на HTTP/2.

Как понять, что сертификат получен?

Команда journalctl -u caddy | grep -i certificate покажет строки certificate obtained successfully. Файлы появятся в /var/lib/caddy/.local/share/caddy/certificates. Ещё быстрее - curl -vI https://ваш-домен и посмотреть строки про TLS-рукопожатие и издателя сертификата.

Сколько ресурсов ест Caddy?

Для нескольких сайтов - десятки мегабайт памяти в покое, одного небольшого VPS (1 vCPU, 1 ГБ RAM) хватает с запасом. Точные числа зависят от трафика и количества одновременных соединений, поэтому проверяйте на своей нагрузке, а не по чужим цифрам.

Можно ли держать Nginx и Caddy на одной машине?

Можно, но не на одних портах. Либо Caddy занимает 80 и 443, а Nginx слушает localhost и служит upstream, либо вы разводите их по разным портам. Одновременно занять 443 они не смогут - второй процесс не стартует.

Коротко

  • Официальный способ установки - apt-репозиторий Caddy на Cloudsmith; в репозитории Ubuntu пакет есть только с 24.04 и заметно старее, в 22.04 его нет.
  • Пакет caddy приносит systemd-сервис, конфиг-заготовку /etc/caddy/Caddyfile и системного пользователя caddy.
  • HTTPS включается сам, если адрес сайта - домен, снаружи доступен хотя бы один из портов 80/443, а A- и/или AAAA-запись ведёт на сервер.
  • Статика - root + file_server; обратный прокси - reverse_proxy localhost:3000.
  • Перед каждым применением - caddy validate, затем systemctl reload caddy (без простоя).
  • Сертификаты и данные ACME - в /var/lib/caddy/.local/share/caddy, логи - journalctl -u caddy.
  • Оставайтесь на Nginx, если нужен тонкий контроль TLS, сложный rewrite, его модули или уже есть большой рабочий конфиг.
PUBLISHED
2 сентября 2026 г.
AUTHOR
HIP-HOSTING
LANGUAGES
EN · RU